#include "filethread.h"
#include <QDataStream>
#include <QDir>
#include "tcpfile.h"
#include "tcpmessage.h"

extern TcpFile *tcpFile;
extern TcpMessage *tcpMessage;

FileThread::FileThread(QTcpSocket *s)
{
    qDebug() << "file thread";
    // 传参来的socket赋值给private中的socket
    this->socket = s;
}


void FileThread::run()
{
    connect(socket,SIGNAL(readyRead()),this,SLOT(slotReadFile()));
    connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(slotBytesWritten(qint64)));
    connect(this, SIGNAL(signalSendFile(QString)), this, SLOT(slotSendFile(QString)));

    timer = new QTimer(this);
    timer->setSingleShot(false);
    timer->setInterval(50);
    connect(timer, SIGNAL(timeout()), this, SLOT(slotFileTimer()));
    timer->start();
    this->exec();
}

// 检测队列是否有需要发送的文件
void FileThread::slotFileTimer()
{
    timeOut += 1;
    // 超时30s 重发
    if(timeOut > 30*20)
    {
        timeOut = 0;
        isSend = false;
    }
    // 队列中有数据，并且不是在发送状态
    if(isSend==false)
    {
        if(sendList.length())
        {
        qDebug() << sendList.first();
        emit signalSendFile(sendList.first());
        }
    }
}

void FileThread::slotReadFile()
{
    QString pathPre = "../data/";
    QDataStream in(socket);
    in.setVersion(QDataStream::Qt_5_0);
    //如果接收到的数据小于等于16个字节，那么是刚开始接收数据，我们保存为头文件信息
    if(bytesReceived<= sizeof(qint64)*2)
    {
        //接收数据总大小信息和文件名大小信息
        if((socket->bytesAvailable() >= sizeof(qint64)*2) && (fileNameSize == 0))
        {
            in >> totalBytesRead >> fileNameSize;
            bytesReceived += sizeof(qint64) * 2;
        }

        //接收文件名，并建立文件
        if((socket->bytesAvailable() >= fileNameSize) && (fileNameSize != 0))
        {
            in >> fileName;
            bytesReceived += fileNameSize;

            // 创建data目录，所有文件都存放于此
            QDir dir;

            if(!dir.exists(pathPre))
                dir.mkpath(pathPre);
            recvFile = new QFile(pathPre + fileName);
            if(!recvFile->open(QFile::WriteOnly))
            {
                qDebug() << "writing file error!";
                return;
            }
        }
        else
            return;
    }

    //如果接收的数据小于总数据，那么写入文件
    if(bytesReceived < totalBytesRead)
    {
        qint64 size = qMin(socket->bytesAvailable(), totalBytesRead-bytesReceived);
        inBlock = socket->read(size);
        bytesReceived += size;
        recvFile->write(inBlock);
        inBlock.resize(0);
    }

    //接收数据完成时
    if(bytesReceived == totalBytesRead)
    {
        qDebug() << "file read all" << fileName;
        // 清空数据
        recvFile->close();
        bytesReceived = 0; // clear for next receive
        totalBytesRead = 0;
        fileNameSize = 0;

        // 判断是否收到token文件
        if(fileName.contains("_token.txt"))
        {
            // 打开token文件
            QFile *tmpfile = new QFile(pathPre + fileName);
            if(!tmpfile->open(QFile::ReadOnly | QIODevice::Text))
            {
                qDebug() << "open token file error!";
                return;
            }
            // 读取token
            QTextStream tmpin(tmpfile);
            QString line = tmpin.readLine();
            token = line.split("#").at(3);
        }
        // 发送应答
        if(!token.isNull())
        {
            qDebug() <<tcpMessage->findSID(token);
            (tcpMessage->threadMap)[tcpMessage->findSID(token)]->sendList << "#MSGSTART#recv_file_over#MSGEND#";
        }
    }
}

void FileThread::slotSendFile(QString path)
{
    if(path.isNull())
        return;
    isSend = true;
    // 打开文件
    sendFile = new QFile(path);
    if(!sendFile->open(QFile::ReadOnly))
    {
        qDebug() << "open file error!";
        return;
    }
    // 文件总大小
    totalBytesWrite = sendFile->size();
    // 打开输出流
    QDataStream sendOut(&outBlock, QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_5_0);
    // 得到文件名字
    QString currentFileName = path.right(path.size() - path.lastIndexOf('/')-1);
    // 写入总大小(先用0站位)、文件名大小(先用0站位)、文件名
    sendOut << qint64(0) << qint64(0) << currentFileName;
    // 这里的总大小是文件名大小等信息和实际文件大小的总和
    totalBytesWrite += outBlock.size();
    bytesToWrite = totalBytesWrite;
    // 返回outBolock的开始，用实际的大小信息代替两个qint64(0)空间
    sendOut.device()->seek(0);
    // 写入总大小、文件名大小
    sendOut<<totalBytesWrite<<qint64((outBlock.size() - sizeof(qint64)*2));
    // 发送头部数据
    bytesToWrite -= socket->write(outBlock);
    // 清空输出流
    outBlock.resize(0);
}

void FileThread::slotBytesWritten(qint64 bytes)
{
    // 发送文件
    if(bytesToWrite>0)
    {
        // 读取一部分数据
        outBlock = sendFile->read(qMin(bytesToWrite, loadSize));
        // 发送数据
        bytesToWrite -= socket->write(outBlock);
        // 清除缓冲区
        outBlock.resize(0);
    }
    else
    {
        sendList.removeFirst();
        isSend = false;
        // 关闭文件
        sendFile->close();
        // 清空数据
        bytesToWrite = 0;
        totalBytesWrite = 0;
        qDebug() <<"file send over...";
    }
}
